#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Ticker.h>
#include <string.h>
/*---------------------------------------------------------------*/
#define mqttPort 1883
// 设置wifi接入信息(请根据您的WiFi信息进行修改)
const char* ssid = "fish";
const char* password = "12345679";
const char* mqttServer = "test.ranye-iot.net";

WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);

//设置定时器1，函数，服务器连接函数，和定时保持心跳
Ticker Ticker_Client;
/*-------------------------------------------------------------*/
String rdata;
char tempdata [10];
char humidata [10];
char compare[3];
char compareFound[3]="fo";
char compareFlame[3]="fl";
char compareTemp[3]="te";
char compareHumi[3]="hu";

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);//初始化LED灯  低点平点亮
  digitalWrite(LED_BUILTIN, HIGH);
  Serial.begin(9600);         //设置串口波特率
  /*--------------------------------------------------------------*/
  //设置ESP8266工作模式为无线终端模式
  WiFi.mode(WIFI_STA);
  Serial.println("start");
  // 连接WiFi
  connectWifi();

  // 设置MQTT服务器和端口号
  mqttClient.setServer(mqttServer, mqttPort);
  mqttClient.setCallback(receiveCallback);

  // 连接MQTT服务器
  connectMQTTServer();
  // Ticker定时对象
  Ticker_Client.attach(3, Tim_Client);
  flame(0);
}
/*----------------------------------------------------------------------------*/
void loop() {
  //如果串口有消息才接受反应
  if (Serial.available() > 0) {
    if (Serial.find("start")) {
//      Serial.println("recevie data");
      delay(100);
      Serial.readBytes(compare, 2);
      /*温度*/
      if (strcmp(compare, compareTemp) == 0)
      {
        Serial.readBytes(tempdata, 2);
        Serial.println(tempdata);
        temp(tempdata);
      }
      /*湿度*/
      if (strcmp(compare, compareHumi) == 0)
      {
        Serial.readBytes(humidata, 2);
        Serial.println(humidata);
        humi(humidata);
      }
      if (strcmp(compare, compareFlame) == 0)
      {
        Serial.println("open flame warning");
        flame(1);
      }
      if (strcmp(compare, compareFound) == 0)
      {
        Serial.println("found man disconver");
        found(1);
      }
    }
  }
}
/*-------------------------------------------------------------*/
/*
  describe:火焰传感器发布主题 0发布off 1发布on
  parma：flame(0)   flame(1)
*/
void flame(int x)
{
  // 建立flame主题并推送消息
  String flameString = "esp8266/flame";
  char publishflame[flameString.length() + 1];
  strcpy(publishflame, flameString.c_str());

  String messageString;
  if (x == 1)
    messageString = "on open flame";
  else
    messageString = "off";
  char publishMsg[messageString.length() + 1];
  strcpy(publishMsg, messageString.c_str());
  // 实现ESP8266向主题发布信息
  mqttClient.publish(publishflame, publishMsg);
}
/*
   describe:温度发布主题
   parma:要发送的数据
*/
void temp(char * data)
{
  // 建立temp主题并推送消息
  String tempString = "esp8266/temp";
  char publishtemp[tempString.length() + 1];
  strcpy(publishtemp, tempString.c_str());

  String messageString;
  messageString = data;

  char publishMsg[messageString.length() + 1];
  strcpy(publishMsg, messageString.c_str());

  // 实现ESP8266向主题发布信息
  mqttClient.publish(publishtemp, publishMsg);
}
/*
   describe:湿度发布主题
   parma:要发送的数据
*/
void humi(char * data)
{
  // 建立humi主题并推送消息
  String DHT11String = "esp8266/humi";
  char publishDHT11[DHT11String.length() + 1];
  strcpy(publishDHT11, DHT11String.c_str());

  String messageString;
  messageString = data;

  char publishMsg[messageString.length() + 1];
  strcpy(publishMsg, messageString.c_str());

  // 实现ESP8266向主题发布信息
  mqttClient.publish(publishDHT11, publishMsg);
}

void mq2(void)
{

}
/*
  describe:HR传感器发布主题 0发布off 1发布on
  parma：flame(0)   flame(1)
*/
void found(int x)
{
  // 建立found主题并推送消息
  String foundString = "esp8266/found";
  char publishfound[foundString.length() + 1];
  strcpy(publishfound, foundString.c_str());

  String messageString;
  if (x == 1)
    messageString = "disconver man";
  else
    messageString = "found nobody";
  char publishMsg[messageString.length() + 1];
  strcpy(publishMsg, messageString.c_str());
  // 实现ESP8266向主题发布信息
  mqttClient.publish(publishfound, publishMsg);
}
// 建立发布主题发布信息
void pubMQTTmsg() {

}

/*
  Ticker ticker;// 建立Ticker用于实现定时功能
  保持MQTT连接，定时心跳
*/
void Tim_Client() {
  if (mqttClient.connected()) { // 如果开发板成功连接服务器
    // 保持心跳
    mqttClient.loop();
  }
  else {                  // 如果开发板未能成功连接服务器
    connectMQTTServer();    // 则尝试连接服务器
    Serial.print("MQTT Server Connect Failed. Client State:");
    Serial.println(mqttClient.state());
  }
}

/*下面是MQTT的函数---------下面不用改动------------------------------------------*/
void connectMQTTServer() {
  // 根据ESP8266的MAC地址生成客户端ID（避免与其它ESP8266的客户端ID重名）
  String clientId = "esp8266-" + WiFi.macAddress();

  // 连接MQTT服务器
  if (mqttClient.connect(clientId.c_str())) {
    Serial.println("MQTT Server Connected.");
    Serial.println("Server Address: ");
    Serial.println(mqttServer);
    subscribeTopic(); // 订阅指定主题
  } else {
    Serial.print("MQTT Server Connect Failed. Client State:");
    Serial.println(mqttClient.state());
    delay(3000);
  }
}

// 订阅指定主题
void subscribeTopic() {
  // 这么做是为确保不同设备使用同一个MQTT服务器测试消息订阅时，所订阅的主题名称不同
  String topicString = "esp8266/control";
  char subTopic[topicString.length() + 1];
  strcpy(subTopic, topicString.c_str());

  // 通过串口监视器输出是否成功订阅主题以及订阅的主题名称
  if (mqttClient.subscribe(subTopic)) {
    Serial.println("Subscribe Topic:");
    Serial.println(subTopic);
  } else {
    Serial.print("Subscribe Fail...");
  }

}

/* 收到信息后的回调函数
    topic 回调函数订阅的主题
    payload 回调函数收到信息的字节
    length 回调函数收到信息的长度
*/
void receiveCallback(char* topic, byte* payload, unsigned int length) {
  //将订阅的控制主题收到的信息通过串口打印出来
  Serial.println("receive messmage");
  int i;
  for (i = 0; i < length; i++)
    Serial.print((char)payload[i]);
}

// ESP8266连接wifi
void connectWifi() {

  WiFi.begin(ssid, password);

  //等待WiFi连接,成功连接后输出成功信息
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi Connected!");
  Serial.println("");
}
